<html><head><meta charset="utf-8"/><title>插入DOM</title></head><body><h1>插入DOM</h1><div class="x-wiki-content x-main-content">
 <p>
  当我们获得了某个DOM节点，想在这个DOM节点内插入新的DOM，应该如何做？
 </p>
 <p>
  如果这个DOM节点是空的，例如，
  <code>
   &lt;div&gt;&lt;/div&gt;
  </code>
  ，那么，直接使用
  <code>
   innerHTML = '&lt;span&gt;child&lt;/span&gt;'
  </code>
  就可以修改DOM节点的内容，相当于“插入”了新的DOM节点。
 </p>
 <p>
  如果这个DOM节点不是空的，那就不能这么做，因为
  <code>
   innerHTML
  </code>
  会直接替换掉原来的所有子节点。
 </p>
 <p>
  有两个办法可以插入新的节点。一个是使用
  <code>
   appendChild
  </code>
  ，把一个子节点添加到父节点的最后一个子节点。例如：
 </p>
 <pre><code>&lt;!-- HTML结构 --&gt;
&lt;p id="js"&gt;JavaScript&lt;/p&gt;
&lt;div id="list"&gt;
    &lt;p id="java"&gt;Java&lt;/p&gt;
    &lt;p id="python"&gt;Python&lt;/p&gt;
    &lt;p id="scheme"&gt;Scheme&lt;/p&gt;
&lt;/div&gt;
</code></pre>
 <p>
  把
  <code>
   &lt;p id="js"&gt;JavaScript&lt;/p&gt;
  </code>
  添加到
  <code>
   &lt;div id="list"&gt;
  </code>
  的最后一项：
 </p>
 <pre><code>var
    js = document.getElementById('js'),
    list = document.getElementById('list');
list.appendChild(js);
</code></pre>
 <p>
  现在，HTML结构变成了这样：
 </p>
 <pre><code>&lt;!-- HTML结构 --&gt;
&lt;div id="list"&gt;
    &lt;p id="java"&gt;Java&lt;/p&gt;
    &lt;p id="python"&gt;Python&lt;/p&gt;
    &lt;p id="scheme"&gt;Scheme&lt;/p&gt;
    &lt;p id="js"&gt;JavaScript&lt;/p&gt;
&lt;/div&gt;
</code></pre>
 <p>
  因为我们插入的
  <code>
   js
  </code>
  节点已经存在于当前的文档树，因此这个节点首先会从原先的位置删除，再插入到新的位置。
 </p>
 <p>
  更多的时候我们会从零创建一个新的节点，然后插入到指定位置：
 </p>
 <pre><code>var
    list = document.getElementById('list'),
    haskell = document.createElement('p');
haskell.id = 'haskell';
haskell.innerText = 'Haskell';
list.appendChild(haskell);
</code></pre>
 <p>
  这样我们就动态添加了一个新的节点：
 </p>
 <pre><code>&lt;!-- HTML结构 --&gt;
&lt;div id="list"&gt;
    &lt;p id="java"&gt;Java&lt;/p&gt;
    &lt;p id="python"&gt;Python&lt;/p&gt;
    &lt;p id="scheme"&gt;Scheme&lt;/p&gt;
    &lt;p id="haskell"&gt;Haskell&lt;/p&gt;
&lt;/div&gt;
</code></pre>
 <p>
  动态创建一个节点然后添加到DOM树中，可以实现很多功能。举个例子，下面的代码动态创建了一个
  <code>
   &lt;style&gt;
  </code>
  节点，然后把它添加到
  <code>
   &lt;head&gt;
  </code>
  节点的末尾，这样就动态地给文档添加了新的CSS定义：
 </p>
 <pre><code>var d = document.createElement('style');
d.setAttribute('type', 'text/css');
d.innerHTML = 'p { color: red }';
document.getElementsByTagName('head')[0].appendChild(d);
</code></pre>
 <p>
  可以在Chrome的控制台执行上述代码，观察页面样式的变化。
 </p>
 <h3>
  insertBefore
 </h3>
 <p>
  如果我们要把子节点插入到指定的位置怎么办？可以使用
  <code>
   parentElement.insertBefore(newElement, referenceElement);
  </code>
  ，子节点会插入到
  <code>
   referenceElement
  </code>
  之前。
 </p>
 <p>
  还是以上面的HTML为例，假定我们要把
  <code>
   Haskell
  </code>
  插入到
  <code>
   Python
  </code>
  之前：
 </p>
 <pre><code>&lt;!-- HTML结构 --&gt;
&lt;div id="list"&gt;
    &lt;p id="java"&gt;Java&lt;/p&gt;
    &lt;p id="python"&gt;Python&lt;/p&gt;
    &lt;p id="scheme"&gt;Scheme&lt;/p&gt;
&lt;/div&gt;
</code></pre>
 <p>
  可以这么写：
 </p>
 <pre><code>var
    list = document.getElementById('list'),
    ref = document.getElementById('python'),
    haskell = document.createElement('p');
haskell.id = 'haskell';
haskell.innerText = 'Haskell';
list.insertBefore(haskell, ref);
</code></pre>
 <p>
  新的HTML结构如下：
 </p>
 <pre><code>&lt;!-- HTML结构 --&gt;
&lt;div id="list"&gt;
    &lt;p id="java"&gt;Java&lt;/p&gt;
    &lt;p id="haskell"&gt;Haskell&lt;/p&gt;
    &lt;p id="python"&gt;Python&lt;/p&gt;
    &lt;p id="scheme"&gt;Scheme&lt;/p&gt;
&lt;/div&gt;
</code></pre>
 <p>
  可见，使用
  <code>
   insertBefore
  </code>
  重点是要拿到一个“参考子节点”的引用。很多时候，需要循环一个父节点的所有子节点，可以通过迭代
  <code>
   children
  </code>
  属性实现：
 </p>
 <pre><code>var
    i, c,
    list = document.getElementById('list');
for (i = 0; i &lt; list.children.length; i++) {
    c = list.children[i]; // 拿到第i个子节点
}
</code></pre>
 <h3>
  练习
 </h3>
 <p>
  对于一个已有的HTML结构：
 </p>
 <ol id="test-list">
  <li class="lang">
   Scheme
  </li>
  <li class="lang">
   JavaScript
  </li>
  <li class="lang">
   Python
  </li>
  <li class="lang">
   Ruby
  </li>
  <li class="lang">
   Haskell
  </li>
 </ol>
 <pre><code>&lt;!-- HTML结构 --&gt;
&lt;ol id="test-list"&gt;
    &lt;li class="lang"&gt;Scheme&lt;/li&gt;
    &lt;li class="lang"&gt;JavaScript&lt;/li&gt;
    &lt;li class="lang"&gt;Python&lt;/li&gt;
    &lt;li class="lang"&gt;Ruby&lt;/li&gt;
    &lt;li class="lang"&gt;Haskell&lt;/li&gt;
&lt;/ol&gt;
</code></pre>
 <p>
  按字符串顺序重新排序DOM节点：
 </p>
 <pre><code class="language-x-javascript">'use strict';
----
// sort list:
----
// 测试:
;(function () {
    var
        arr, i,
        t = document.getElementById('test-list');
    if (t &amp;&amp; t.children &amp;&amp; t.children.length === 5) {
        arr = [];
        for (i=0; i&lt;t.children.length; i++) {
            arr.push(t.children[i].innerText);
        }
        if (arr.toString() === ['Haskell', 'JavaScript', 'Python', 'Ruby', 'Scheme'].toString()) {
            console.log('测试通过!');
        }
        else {
            console.log('测试失败: ' + arr.toString());
        }
    }
    else {
        console.log('测试失败!');
    }
})();
</code></pre>
</div>
</body></html>